﻿using System;
using System.ComponentModel;
using Microsoft.WowAddonStudio.FrameXml.Serialization.Support;
using NUnit.Framework;

namespace Microsoft.WowAddonStudio.FrameXml.Serialization.Tests
{
	[TestFixture]
	public class PropertyBagTest
	{
		/// <summary>
		/// Gets or sets the string property.
		/// </summary>
		/// <value>The string property.</value>
		[DefaultValue("DefaultValue")]
		public string StringProperty { get; set; }

		[Test]
		public void BackSimplePropertyTest()
		{
			var propertyBag = new PropertyBag(this);

			propertyBag.SetValue("IntProperty", 5);
			propertyBag.SetValue("FloatProperty", 0.5f);
			propertyBag.SetValue("StringProperty", "Value");

			Assert.AreEqual(5, propertyBag["IntProperty"]);
			Assert.AreEqual(0.5f, propertyBag["FloatProperty"]);
			Assert.AreEqual("Value", propertyBag["StringProperty"]);
		}

		[Test]
		public void UndefinedPropertyTest()
		{
			var propertyBag = new PropertyBag(this);

			Assert.AreEqual(null, propertyBag.GetValue<string>("UndefinedStringProperty"));
			Assert.AreEqual(null, propertyBag.GetValue<int?>("UndefinedNullableIntProperty"));
			Assert.AreEqual(0, propertyBag.GetValue<int>("UndefinedIntProperty"));
		}

		[Test]
		[ExpectedException(typeof (InvalidCastException))]
		public void PropertyTypeMismatchTest()
		{
			var propertyBag = new PropertyBag(this);

			propertyBag.SetValue("IntProperty", 5);

			// Try to retrieve the value of the IntProperty as float
			propertyBag.GetValue<float>("IntProperty");
		}

		[Test]
		public void ValueInheritanceTest()
		{
			// Create the property bags and set inheritance
			var inheritedPropertyBag = new PropertyBag(this);
			var propertyBag = new PropertyBag(this)
			                  	{
			                  		InheritedPropertyBag = inheritedPropertyBag
			                  	};

			// Set values in the inherited property bag
			inheritedPropertyBag.SetValue("InheritedProperty", 10);
			inheritedPropertyBag.SetValue("OverridenProperty", "InheritedValue");

			// Set values in the property bag
			propertyBag.SetValue("OverridenProperty", "OverridenValue");

			Assert.AreEqual(10, propertyBag["InheritedProperty"]);
			Assert.AreEqual("OverridenValue", propertyBag["OverridenProperty"]);

			// Reset the value of OverridenProperty
			propertyBag.ResetValue("OverridenProperty");

			Assert.AreEqual("InheritedValue", propertyBag["OverridenProperty"]);
		}

		[Test]
		public void DefaultValueTest()
		{
			var propertyBag = new PropertyBag(this);

			// Assert that the property bag recognizes and returns the default value for the property
			Assert.AreEqual("DefaultValue", propertyBag["StringProperty"]);

			// Set an explicit value for the property and assert
			propertyBag.SetValue("StringProperty", "NewValue");

			Assert.AreEqual("NewValue", propertyBag["StringProperty"]);
		}

		[Test]
		public void NotifyPropertyChangedTest()
		{
			var propertyBag = new PropertyBag(this);

			int raisedCount = 0;

			propertyBag.PropertyChanged += delegate(object sender, PropertyChangedEventArgs e)
			                               	{
			                               		raisedCount++;

			                               		Assert.AreSame(propertyBag, sender);
			                               		Assert.AreEqual("TestProperty", e.PropertyName);
			                               	};

			// Set the value of the property twice
			propertyBag.SetValue("TestProperty", "Value");
			propertyBag.SetValue("TestProperty", "NewValue");

			// Assert current value of the property
			Assert.AreEqual("NewValue", propertyBag.GetValue<string>("TestProperty"));

			// Reset the value of the property
			propertyBag.ResetValue("TestProperty");

			// Assert that property has no value and PropertyChanged event was raised three times
			Assert.IsNull(propertyBag.GetValue<string>("TestProperty"));
			Assert.AreEqual(3, raisedCount);
		}
	}
}